package com.lx.spring.anno.mybatis;

import lombok.Data;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.List;

public class SqlSession {

    public <T> T getMapper(Class<T> cls) {
//        UserMapper mapper = getMapper(UserMapper.class);
        // JDK 动态代理
        //创建代理对象
        return (T) Proxy.newProxyInstance(cls.getClassLoader(),
                new Class[]{cls},
                //方法拦截器 放回值就是业务方法的返回值
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, //代理对象
                                         Method method, //执行方法
                                         Object[] args //方法参数
                    ) throws Throwable {
                        System.out.println("method = " + method);
                        System.out.println("args = " + Arrays.toString(args));
                        System.out.println("method.getReturnType() = " + method.getReturnType());


                        Select annotation = method.getAnnotation(Select.class);
                        if (annotation != null) {
                            String sql = annotation.value();
                            if(method.getParameterCount() == 1){
                                 // 单参数，排除实体对象

                                sql = sql.replaceAll("#\\{\\w+}", "?");
                                System.out.println("sql = " + sql);
                                System.out.println("参数 = " + Arrays.toString(args));

                            }else{
                                // 多参数 : 实体对象
                            }

                        }
                        return null;
                    }
                });
    }

    public static void main(String[] args) {
        SqlSession sqlSession = new SqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.selectById(100);
        mapper.selectLikeName("张三");
    }

}
@Retention(RetentionPolicy.RUNTIME)
@interface Insert{
    String value();
}
@interface Update{
    String value();
}
@Retention(RetentionPolicy.RUNTIME)
@interface Select{
    String value();
}
@Retention(RetentionPolicy.RUNTIME)
@interface Delete{
    String value();
}
@Retention(RetentionPolicy.RUNTIME)
@interface Param{
    String value();
}



    // 实体类
    @Data
    class User{
        Integer id;
        String username;
        String password;
    }
    // Mapper 接口
    interface UserMapper {
        @Insert("insert into test_user (username, password) values(#{usr},#{pwd})")
        void insert(@Param("usr") String username, @Param("pwd") String password);
        @Update("update test_user set username = #{username}, password = #{password} where id = #{id}")
        int update(User user);
        @Select("select * from test_user where id = #{id}")
        User selectById(int id);
        @Select("select * from test_user where username like #{uname}")
        List< User > selectLikeName(String username);
    }
    // 提示: 如何获取方法返回值泛型类型? 请参考以下代码
    class Demo {
        public static void main(String[] args) throws Exception {
            // 获取 selectLikeName 方法返回值 List 的泛型
            Class aClass = getGenericReturnType(UserMapper.class,
                    "selectLikeName",
                    String.class);
            System.out.println("返回值List的泛型类型 = " + aClass);
        }
        public static Class getGenericReturnType(Class cls, String methodName,Class...classes){
            try{
                // 获取方法对象
                Method declaredMethod = cls.getDeclaredMethod(methodName, classes);
                // 获取返回值类型 Type (注意:Type不是Class)
                Type type = declaredMethod.getGenericReturnType();
                // 转型 ParameterizedType
                ParameterizedType pType=(ParameterizedType)type;
                // 获取泛型数组中的第一个泛型类型
                Class ret = (Class) pType.getActualTypeArguments()[0];
                return ret;
            } catch (Exception e){
                throw new RuntimeException(e);
            }
        }
    }

